home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-03-19 | 19.9 KB | 528 lines | [TEXT/MPS ] |
- #/******************* This is a full line in MPW printing on an 8.5 x 11, in Courier 9 ******************/
- #########################################################################
- #########################################################################
- ## Copyright Apple Computer, Inc. 1992-1997
- ## All rights reserved
- #########################################################################
- #########################################################################
- #
- # Library: Arbitrator.vu
- #
- # Version: 2.1.1
- # Description:
- # This script provides arbitration and other services for scripts using the Launchquit
- # Engine (see LaunchQuit.lib) running on the same host. Due to limitations of VU, inter-host
- # communications can not occur without an external tool. Hopefully someone will write such a
- # tool but for now, one host is the entire universe.
- #
- # The most important task of the Arbitrator is to prevent two targets from launching the same
- # application at the same time. This is necessary if the application checks for serial number
- # conflicts over the network, which is a very nasty habit, discouraged by Apple and disparaged
- # by network managers everywhere. However, it is a fact of life that some applications not only
- # refuse to run under such a circumstance, they actually undo their serial number registration.
- # All subsequent launches fail because the script does not anticipate the registration dialog.
- #
- # Another task is to store how many test cases a script has completed. If the script stops
- # unexpectedly, the user can simply restart the script without having to comment out the
- # completed test cases. On startup, the script checks with the Arbitrator to see if it
- # completed the last run and determines where it should resume.
- #
- # These are the status variables maintained by the script:
- # myActors := { [ 'actorName' [, … ] };
- # appsInUse := { [{application1, actorName}][, {application2, actorName}]… }
- # resumees := { [{ actor1, lastTestCase1}][, {actor2, lastTestCase2}]… }
- # Contains:
- # PrepareArbitrator()
- # UsingArbitrator()
- # ReleaseArbitrator()
- # AcquireID()
- # ReleaseID()
- #
- # History:
- # Date: By: Changes:
- # 12/15/92 SBR Created
- # 09/29/94 SBR Changed to use Arbitrator external tool
- # 07/21/95 SBR Added AutoDestruct feature
- # 01/30/97 SBR Deleted older exception code and comments.
- #
- # Version Date By Comment
- # ======= ======== === =======
- # 1.0.0 02/12/97 JAS Added 'vers' resources to library.
- # These should always match tool version when tool is revved.
- #
- #########################################################################
- #########################################################################
-
- Libraries
- "Report.lib";
-
-
- tool Arbitrator s:'Arbi'
- begin
- # Services specific to Arbitrator:
-
- # To lock an ID (a list containing one or more values, each value can be a
- # Boolean, string, integer, or list type)
- Service "LockID"( 'list', 'symbol', 'undefined' ) return 'symbol';
-
- # first parameter is the ID (a list) to lock as a resource acquisition
- # second parameter is Boolean: true means lock, false means unlock
- # third parameter is the autodestruct 'integer' (used for locking only)
- # return value is Boolean, true means success, false means failure
-
-
- # To set up an autodestruct ID
- Service "AutoDestruct"( ) return 'symbol';
-
- # call this once per script asynchronously and provide the job ID when you lock names
- # when a script exits, the names it locked will be unlocked automatically
- # return value is Boolean, true means success, false means failure
-
-
- # To dump all locked IDs
- Service "DumpIDs"( ) return 'list';
-
- # call this for debugging the Arbitrator LockID service
- # return value is the list of locked IDs
-
- end;
-
- #########################################################################
- # task PrepareArbitrator(v_level)
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # Description: Ensures the Arbitrator is ready to receive a request. Use this
- # routine so in the future if the Arbitrator becomes an External Tool
- # or anything else but a script, we do not use openSession().
- #
- # NOTE: The hidden global gArbitratorIsPrepared can have two values:
- # undefined or an integer. Undefined indicates the Arbitrator is in
- # the released (unknown) state. A call to this task with the global
- # containing undefined will cause the task to try preparing the
- # Arbitrator, and the global will be assigned the integer value of
- # the asynchronous job ID from the AutoDestruct service. All
- # subsequent calls to this task will just return the value of
- # gArbitratorIsPrepared. To reset the value of this hidden global
- # to undefined, call ReleaseArbitrator().
- #
- # Parameters: v_level: verbosity level for reporting
- # Returns: true if successful, false if not
- # Examples: PrepareArbitrator();
- # Assumptions: VU 2.0.1
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # History:
- # 01/14/94 SBR Created
- # 09/29/94 SBR Changed to use Arbitrator external tool
- #########################################################################
- task PrepareArbitrator(v_level := 1)
- begin
- global gArbitratorIsPrepared;
-
- if isUndefined(gArbitratorIsPrepared) # First time through, make a
- begin # new session, wait if needed
- theResult := Arbitrator('initialize');
- if theResult[1]
- begin
- RIncomplete("PrepareArbitrator initialize: {theResult}",v_level);
- end;
- else
- begin
- theResult := Arbitrator('AutoDestruct') async:true;
- if theResult[1] = 1 # normal asynchronous result
- begin
- gArbitratorIsPrepared := theResult[2]; # store job ID for AutoDestruct
- end;
- else
- begin
- RIncomplete("PrepareArbitrator AutoDestruct: {theResult}",v_level);
- gArbitratorIsPrepared := undefined;
- end;
- end;
- end;
- # else if gArbitratorIsPrepared # just check old session
- # begin
- # theResult := Arbitrator('initialize');
- # if theResult[1]
- # begin
- # RIncomplete("PrepareArbitrator re-initialize: {theResult}",v_level);
- # RStatus("The Arbitrator disappeared after it was prepared!",v_level);
- # gArbitratorIsPrepared := undefined;
- # end;
- # end;
-
- return gArbitratorIsPrepared;
- end;
-
-
- #########################################################################
- # task UsingArbitrator(v_level)
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # Description: Verifies the Arbitrator is supposed to be ready to receive a request.
- # Just returns the value of the global gArbitratorIsPrepared. Will not
- # prepare the Arbitrator if it is not ready.
- # Parameters: v_level: verbosity level for reporting
- # Returns: true if global is true, false if not
- # Examples: needToRegister := UsingArbitrator();
- # Assumptions: VU 2.0.1
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # History:
- # 01/14/94 SBR Created
- #########################################################################
- task UsingArbitrator(v_level := 5)
- begin
- global gArbitratorIsPrepared;
-
- if isUndefined(gArbitratorIsPrepared)
- begin
- return false;
- end;
- else
- return gArbitratorIsPrepared;
- end;
-
-
- #########################################################################
- # task ReleaseArbitrator(v_level)
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # Description: Releases the Arbitrator from the session created by PrepareArbitrator().
- # In the future this may quit the External Tool, but for now we
- # assume other scripts are also using the tool, so do not quit.
- # Parameters: v_level: verbosity level for reporting
- # Returns: nothing
- # Examples: ReleaseArbitrator();
- # Assumptions: VU 2.0.1
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # History:
- # 01/14/94 SBR Created
- # 09/29/94 SBR Changed to use Arbitrator external tool
- #########################################################################
- task ReleaseArbitrator(v_level := 5)
- begin
- global gArbitratorIsPrepared;
-
- if not gArbitratorIsPrepared
- RIncomplete("ReleaseArbitrator: Arbitrator is not prepared, can not release.",1);
-
- gArbitratorIsPrepared := undefined;
- end;
-
-
- #########################################################################
- # task AcquireID( pID, v_level )
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # Description: Uses the Arbitrator to reserve a resource for exclusive use.
- # See the Arbitrator Script for more explanations.
- # Parameters: pID: The ID (a list) to lock. It must be non-empty, but it
- # may contain Boolean, string, integer, and list types.
- # v_level: verbosity level for reporting
- # Returns: true if successful, false if not
- # Examples: AcquireID( {'application','4th Dimension 2.2.3@'} )
- # AcquireID( {'host folder','full:path:name',42} )
- # Assumptions: VU 2.1
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # History:
- # 02/18/95 SBR created
- #########################################################################
- task AcquireID( pID, v_level := 2 )
- begin
- tAutoDestructCode := PrepareArbitrator();
- if isUndefined(tAutoDestructCode)
- return false;
-
- arbResponse := Arbitrator( 'LockID', pID, true, tAutoDestructCode );
-
- if arbResponse[1] # an error occurred
- begin
- return RIncomplete("Arbitrator LockID: a tool error occurred: {arbResponse}.",v_level);
- end;
-
- if arbResponse[2] # no error occurred, acquire succeeded
- begin
- tIDIsLocked := true;
- end;
- else # no error occurred, acquire failed
- begin
- arbWaitTime := 60;
- RStatus("Waiting {arbWaitTime} seconds for ID {pID} to be unlocked.",v_level);
- wait(arbWaitTime);
- end;
- return tIDIsLocked;
- end;
-
-
- #########################################################################
- # task ReleaseID( pID, v_level )
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # Description: Uses the Arbitrator to unlock a resource so others can use it.
- # See the Arbitrator Script for more explanations.
- # Parameters: pID: The ID (a list) to unlock.
- # v_level: verbosity level for reporting
- # Returns: true if successful, false if not
- # Examples: ReleaseID( {'application','4th Dimension 2.2.3@'} )
- # Assumptions: VU 2.1
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # History:
- # 02/18/95 SBR created
- #########################################################################
- task ReleaseID( pID, v_level := 2 )
- begin
- if not PrepareArbitrator()
- return false;
-
- arbResponse := Arbitrator( 'LockID', pID, false );
-
- if arbResponse[1] # an error occurred
- begin
- return RIncomplete("ReleaseID: Arbitrator tool error occurred: {arbResponse}.",v_level);
- end;
-
- if arbResponse[2] # no error occurred, release succeeded
- begin
- return true;
- end;
- else # no error occurred, release failed
- begin
- return false;
- end;
- end;
-
-
- #########################################################################
- # script Arbitrator( Verbosity_Level := 2, Quick_Waits := false )
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # Description: The script which provides the Arbitrator services. It is a large
- # loop, which looks for actors not yet connected and tries to open a
- # VU message session with each of them. Once connected, it loops waiting
- # for messages from each one. When it receives a message it responds
- # immediately depending on the contents.
- #
- # After every iteration of the loop, the script waits for a short time
- # to allow other scripts to execute. This idleTime is autmatically
- # adjusted based on the level of activity. If there are no messages
- # from any actors, the idleTime is slightly increased until it
- # reaches 15 seconds, which is the longest reasonable time to wait.
- # If there are any messages from other actors during an iteration, the
- # idleTime is slightly reduced until it reaches a minimum of 2 seconds.
- #
- # If you want to keep the idleTime low for experimenting and bypass
- # the automatic adjustment, use the Quick_Waits script parameter.
- # Parameters: Verbosity_Level: set global verbosity level for reporting
- # Quick_Waits: Boolean true: idleTime = 2 seconds
- # Boolean false: adjust idleTime automatically
- # integer > 0: idleTime = Quick_Waits seconds
- # integer = 0: adjust idleTime automatically
- # Returns: true if successful, false if not
- # Examples: PrepareArbitrator();
- # Assumptions: VU 2.0.1
- #∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞
- # History:
- # 12/15/92 SBR Created
- # 01/14/94 SBR Added auxilliary tasks
- # 02/02/94 SBR Formatted to our script standards, added comments,
- # improved Quick_Waits parameter behavior.
- # 02/02/94 SBR Changed timeout from 0 to 120 seconds for receiving the
- # subsequent messages in a list, e.g. this makes a
- # registration request atomic. This is to try and fix the
- # synchronization problems with multiple scripts.
- #########################################################################
- # script Arbitrator ( Verbosity_Level := 2, Quick_Waits := false )
- # begin
- # appsInUse := {};
- # myActors := {};
- # resumees := {};
- #
- # rPushVerbosity(Verbosity_Level);
- # idleTime := 10;
- #
- # # check if Arbitrator is already running in another place, exit if true
- # actorName(" Arbitrator"); #set for easy NoteBook/Script Parameter window selection
- # if match [actor t:"Arbitrator"]!
- # begin
- # RStatus("Another actor is already running the Arbitrator script on this host.", 1);
- # exit;
- # end;
- # else begin
- # actorName("Arbitrator");
- # RStatus("This actor is now the Arbitrator for this host.", 1);
- # end;
- #
- # while true # the main loop in the script
- # begin
- # # get list of actors who are not registered; remove the Arbitrator
- # match [actor t:$allActors];
- #
- # allActors := remove(isMember('Arbitrator', allActors), allActors);
- # newActors := {};
- #
- # for each thisActor in allActors
- # if not isMember(thisActor, myActors)
- # newActors := newActors + {thisActor};
- # if newActors
- # #println "∂nnewActors = ",newActors;
- #
- # # if any have not opened a session with Arbitrator try an openSession
- # for each newActor in newActors
- # begin
- # if connect_to(newActor, 0) # do not wait, just create an outstanding request
- # begin
- # myActors := myActors + {newActor};
- # resumeValue := assoc(newActor, resumees);
- # if isUndefined(resumeValue)
- # begin
- # resumees := resumees + {{newActor,0}};
- # resumeValue := 0;
- # end;
- # println "∂nopenSession with {newActor}";
- # end;
- # end;
- #
- # # check for service requests and do them
- # for each thisActor in myActors
- # begin
- # #println "Checking actor: {thisActor} after waiting {idleTime}";
- # myMessage := false;
- # if not match [actor t:thisActor]! #actor aborted: remove it and it's apps
- # begin
- # println "ACTOR {thisActor} SUDDENLY DISAPPEARED!";
- # myMessage := 'deleteActor';
- # end;
- #
- # if not myMessage #i.e. myMessage is not 'deleteActor'
- # myMessage := receive_list(thisActor, 1, 0)[1];
- #
- # if myMessage
- # begin
- # println ' ';
- # if myMessage = 'beginTC'
- # begin
- # theTestCase := receive_list(thisActor, 1, 120)[1]; # wait for 2nd string
- # if theTestCase
- # begin
- # println "{thisActor} began test case: '", theTestCase, "'; no response needed.";
- # resumees := replace({thisActor, theTestCase},
- # isMember({thisActor, assoc(thisActor,resumees)}, resumees), resumees);
- # end;
- # end;
- #
- # else if myMessage ~= /resume≈/
- # begin
- # println "{thisActor} requested '{myMessage}'";
- # resumeValue := assoc(thisActor, resumees);
- # println "resumees: ",resumees;
- # println "resumeValue: ",resumeValue;
- # if resumeValue = 0 begin
- # myMessage := 'resumeReset';
- # end;
- # else returnMessage := {thisActor, resumeValue};
- # if (myMessage = 'resumeReset')
- # begin
- # if not (resumeValue = 0)
- # resumees := replace({thisActor, 0}, isMember({thisActor, resumeValue},
- # resumees), resumees);
- # returnMessage := {thisActor,'resumeReset'};
- # end;
- # send_list(thisActor, returnMessage);
- # end;
- #
- # else if myMessage = 'useApplication'
- # begin
- # theAppToUse := receive_list(thisActor, 1, 120)[1]; # wait for 2nd string
- # if theAppToUse
- # begin
- # println "{thisActor} requested 'useApplication {theAppToUse}'";
- # println "appsInUse before registering app: {appsInUse}";
- # appUser := assoc(theAppToUse, appsInUse);
- # if not appUser
- # begin
- # appsInUse := appsInUse + {{theAppToUse, thisActor}};
- # println "appsInUse after registering app: {appsInUse}";
- # println "myActors after registering app: {myActors}";
- # send_list(thisActor, {thisActor, 'useApplication', theAppToUse});
- # println "gave {thisActor} permission to 'useApplication {theAppToUse}'";
- # end;
- # else begin
- # send_list(thisActor, {thisActor, "it is in use by {appUser}", theAppToUse});
- # println "Denied {thisActor} permission to 'useApplication {theAppToUse}'";
- # end;
- # end;
- # end;
- #
- # else if myMessage = 'quitApplication'
- # begin
- # theAppToQuit := receive_list(thisActor, 1, 120)[1]; # wait for 2nd string
- # if theAppToQuit
- # begin
- # println "{thisActor} requested 'quitApplication {theAppToQuit}'";
- # println "appsInUse before quitting app: {appsInUse}";
- # appUser := assoc(theAppToQuit, appsInUse);
- #
- # if not appUser #give permission anyway if not registered
- # begin
- # send_list(thisActor, {theActor, 'quitApplication', theAppToQuit});
- # println "'{theAppToQuit}' is not registered to 'useApplication {theAppToQuit}'";
- # println "gave {thisActor} permission to 'quitApplication {theAppToQuit}'";
- # end;
- # else if appUser = thisActor #delete the app registration
- # begin
- # appsInUse := remove(isMember({theAppToQuit, appUser}, appsInUse), appsInUse);
- # println "appsInUse after quitting app: {appsInUse}";
- # send_list(thisActor, {thisActor, 'quitApplication', theAppToQuit});
- # println "gave {thisActor} permission to 'quitApplication {theAppToQuit}'";
- # end;
- # else begin
- # send_list(thisActor, {thisActor,
- # "'{theAppToQuit}' registered for use by {appUser}", theAppToQuit});
- # println "denied {thisActor} permission to 'quitApplication {theAppToQuit}'";
- # end;
- # end;
- # end;
- #
- # else if myMessage = 'disconnect'
- # begin
- # println "{thisActor} requested 'disconnect'";
- # send_list(thisActor, {thisActor, 'disconnect'});
- # myMessage := 'deleteActor';
- # end;
- #
- # if myMessage = 'deleteActor'
- # begin
- # println "Arbitrator requested 'deleteActor {thisActor}'";
- # index := 1;
- # for i := 1 to card appsInUse
- # begin
- # if appsInUse[index][2] = thisActor
- # appsInUse := remove(index, appsInUse);
- # else index := index + 1;
- # end;
- # println "appsInUse after un-registering {thisActor}'s apps: {appsInUse}";
- # myActors := remove(isMember(thisActor, myActors), myActors);
- # println "myActors after un-registering {thisActor}: {myActors}";
- # temp := assoc(thisActor,resumees);
- # if temp
- # println "actor {thisActor} will resume at {temp}";
- # disconnect_from(thisActor);
- # end;
- #
- # if idleTime > 10
- # idleTime := 10; #shorten wait when busy
- # else if idleTime >= 2
- # idleTime := idleTime - 2;
- # end; #if myMessage
- # else if idleTime <= 13
- # idleTime := idleTime + 2; #lengthen wait when idle, max 15 sec
- #
- # if Quick_Waits
- # begin
- # if typeOf(Quick_Waits) = 'Boolean'
- # idleTime := 2;
- # else if typeOf(Quick_Waits) = 'integer'
- # idleTime := Quick_Waits;
- # end;
- #
- # wait(idleTime); # give the other scripts time
- # end; #for each thisActor in myActors
- #
- # end;
- # end;
-
-
-